﻿using Plugins;
using Plugins.Base.Common;
using Plugins.UserControls;
using TechnicalIndicators.DateBased;
using TechnicalIndicators.QuotationBased;

namespace SMAPlugin.Common
{
	internal class LastFastCrossProcessor
	{
		#region Attributes

		private readonly DecisionEngineData _data;
		private readonly HourSelectorData _hourSettings;
		private readonly MovingAverage _slowSMAGenerator;
		private readonly MovingAverage _fastSMAGenerator;
		private readonly LastValueGenerator _lastValueGenerator;
		private readonly StrategyControlData _strategySettings;
		private readonly OperationManager _operationManager;

		#endregion

		#region Public Methods

		public LastFastCrossProcessor(DecisionEngineData data, HourSelectorData hourSettings, MovingAverage slowSMAGenerator, MovingAverage fastSMAGenerator, LastValueGenerator lastValueGenerator, StrategyControlData strategySettings, OperationManager operationManager)
		{
			_data = data;
			_hourSettings = hourSettings;
			_slowSMAGenerator = slowSMAGenerator;
			_fastSMAGenerator = fastSMAGenerator;
			_lastValueGenerator = lastValueGenerator;
			_strategySettings = strategySettings;
			_operationManager = operationManager;
		}

		public void SetState(DecisionEngineStateBase state)
		{
			_data.State = state;

			if (state == DecisionEngineState.WaitingOpen)
			{
				this.ProcessWaitingOpen();
			}
			else if (state == DecisionEngineState.WaitingSlowAverage)
			{
				this.ProcessWaitingSlowAverage();
			}
			else if (state == DecisionEngineState.WaitingCrossUp)
			{
				this.ProcessWaitingCrossUp();
			}
			else if (state == DecisionEngineState.WaitingCrossDown)
			{
				this.ProcessWaitingCrossDown();
			}
			else if (state == DecisionEngineState.OnLongPossition)
			{
				this.ProcessOnLongPossition();
			}
			else if (state == DecisionEngineState.OnShortPossition)
			{
				this.ProcessOnShortPossition();
			}
			else if (state == DecisionEngineState.DayClosed)
			{
				this.ProcessDayClosed();
			}
		}

		#endregion

		private void ProcessWaitingOpen()
		{
			if (_data.LastQuotation.Date.TimeOfDay > _hourSettings.LastOpen)
			{
				this.SetState(DecisionEngineState.DayClosed);
			}
			else if (_data.LastQuotation.Volume > 0)
			{
				this.SetState(DecisionEngineState.WaitingSlowAverage);
			}
		}

		private void ProcessWaitingSlowAverage()
		{
			if (_data.LastQuotation.Date.TimeOfDay > _hourSettings.LastOpen)
			{
				this.SetState(DecisionEngineState.DayClosed);
			}
			else if (_slowSMAGenerator.LastValue != null)
			{
				if (_slowSMAGenerator.LastValue.Y < _fastSMAGenerator.LastValue.Y)
				{
					this.SetState(DecisionEngineState.WaitingCrossUp);
				}
				else if (_slowSMAGenerator.LastValue.Y > _fastSMAGenerator.LastValue.Y)
				{
					this.SetState(DecisionEngineState.WaitingCrossDown);
				}
			}
		}

		private void ProcessWaitingCrossUp()
		{
			if (_data.LastQuotation.Date.TimeOfDay > _hourSettings.LastOpen)
			{
				this.SetState(DecisionEngineState.DayClosed);
			}
			else if (_slowSMAGenerator.LastValue.Y > _fastSMAGenerator.LastValue.Y)
			{
				this.SetState(DecisionEngineState.WaitingCrossDown);
			}
			else if (_data.PreviousLastValue < _data.PreviousFastValue && _lastValueGenerator.LastValue.Y > _fastSMAGenerator.LastValue.Y && _data.LastQuotation.Sellers[0].Quantity >= _strategySettings.Volume)
			{
				_operationManager.OpenLongPossition(_strategySettings.Volume);
				this.SetState(DecisionEngineState.OnLongPossition);
			}
		}

		private void ProcessWaitingCrossDown()
		{
			if (_data.LastQuotation.Date.TimeOfDay > _hourSettings.LastOpen)
			{
				this.SetState(DecisionEngineState.DayClosed);
			}
			else if (_slowSMAGenerator.LastValue.Y < _fastSMAGenerator.LastValue.Y)
			{
				this.SetState(DecisionEngineState.WaitingCrossUp);
			}
			else if (_data.PreviousLastValue > _data.PreviousFastValue && _lastValueGenerator.LastValue.Y < _fastSMAGenerator.LastValue.Y && _data.LastQuotation.Buyers[0].Quantity >= _strategySettings.Volume)
			{
				_operationManager.OpenShortPossition(_strategySettings.Volume);
				this.SetState(DecisionEngineState.OnShortPossition);
			}
		}

		private void ProcessOnLongPossition()
		{
			if (_data.LastQuotation.Date.TimeOfDay >= _hourSettings.ForcedCloseTime || _lastValueGenerator.LastValue.Y < _fastSMAGenerator.LastValue.Y && _data.LastQuotation.Buyers[0].Quantity >= _strategySettings.Volume)
			{
				_operationManager.CloseLongPossition();
				this.SetState(DecisionEngineState.WaitingCrossUp);
			}
		}

		private void ProcessOnShortPossition()
		{
			if (_data.LastQuotation.Date.TimeOfDay >= _hourSettings.ForcedCloseTime || _lastValueGenerator.LastValue.Y > _fastSMAGenerator.LastValue.Y && _data.LastQuotation.Sellers[0].Quantity >= _strategySettings.Volume)
			{
				_operationManager.CloseShortPossition();
				this.SetState(DecisionEngineState.WaitingCrossDown);
			}
		}

		private void ProcessDayClosed()
		{
			if (_data.LastQuotation.Date.TimeOfDay < _hourSettings.LastOpen && (_data.LastQuotation.Date.Date != _data.PreviousQuotation.Date.Date || _data.LastQuotation.Date < _data.PreviousQuotation.Date))
			{
				_lastValueGenerator.Clear();
				_slowSMAGenerator.Clear();
				_fastSMAGenerator.Clear();

				_lastValueGenerator.Start();
				_slowSMAGenerator.Start();
				_fastSMAGenerator.Start();

				this.SetState(DecisionEngineState.WaitingOpen);
			}
		}
	}
}
